
#include"Allocator.hpp"
#include"../Concurrency/TimeStamp.hpp"
#include"MemItem.hpp"
#include<new>
#include<cassert>
#include<stdlib.h>
#include"./TypesDef.hpp"

namespace MMFAlloc{

#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif


Allocator::Allocator(u64 capacity, u32 blockSize, const std::thread::id& thdId)
:
mCapacity(capacity),
mBlockSize(blockSize),
mInitialSize(capacity),
mThradId(thdId)
{
    assert(capacity > 0 && blockSize > 0);
    
    mCreateTime = MMF::TimeStamp::GetUsTime().count();

    for (int i = 0; i < capacity; i++)
        mFree.push_back(AllocItem());
}


Allocator::~Allocator()
{
    for (auto& v: mInUse)
    {
        free(v->Address());
        v->~MemoryItem();
        free(v);
    }
    
    for (auto& v: mFree)
    {
        free(v->Address());
        v->~MemoryItem();
        free(v);
    }
}


u32 Allocator::BlockSize()
{
    return mBlockSize;
}


u64 Allocator::Capacity()
{
    return mCapacity;
}


MemoryItem* Allocator::AllocItem()
{
    //创建item
    void *itemMem = malloc(sizeof(MemoryItem));
    MemoryItem *mi = new (itemMem) MemoryItem(mBlockSize, mThradId);

    //创建内存
    mi->mBuff = malloc(mBlockSize);

    return mi;
}


void Allocator::Grow()
{
    for (auto i = 0u; i < mInitialSize; i++)
        mFree.push_back(AllocItem());
}


void* Allocator::Alloc()
{
    mLastAccessTime = MMF::TimeStamp::GetUsTime().count();
    MemoryItem* mi = nullptr;
    
    mLock.Lock();
    
    if (mFree.size() == 0)
        Grow();
    
    mi = mFree.front();
    mFree.pop_front();
    mInUse.insert(mi);
    mi->OnAccess();
    
    mLock.Unlock();
    
    return mi->Address();
}


void Allocator::Free(void* addr)
{
    mLastAccessTime = MMF::TimeStamp::GetUsTime().count();
    MemoryItem* mi = (MemoryItem*)addr - 1;
    
    mLock.Lock();
    
    auto iter = mInUse.find(mi);
    if (iter != mInUse.end())
    {
        mInUse.erase(iter);
        mFree.push_back(mi);
    }
    
    mLock.Unlock();
}


void Allocator::Sharink()
{
    time_t curTime = MMF::TimeStamp::GetUsTime().count();
    
    mLock.Lock();
    if (curTime - mLastAccessTime > 1000 * 1000 * 30)
    {
        if (mFree.size() >= mInitialSize * 2)
        {
            for (auto i = 0u; i < mInitialSize; i++)
            {
                MemoryItem* mi = mFree.front();
                mFree.pop_front();
                free(mi->Address());
                mi->~MemoryItem();
                free(mi);
            }
        }
    }
    else if (curTime - mLastAccessTime > 1000 * 1000 * 60 * 5)
    {
        auto iter = mFree.begin();
        while(iter != mFree.end())
        {
            MemoryItem* mi = *iter;
            mFree.pop_front();
            free(mi->Address());
            mi->~MemoryItem();
            free(mi);
        }
        
        mFree.clear();
    }
    
    mLock.Unlock();
}




}
